Add gtk_style_context_cancel_animations()
authorCarlos Garnacho <carlosg@gnome.org>
Mon, 10 Jan 2011 02:31:35 +0000 (03:31 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Mon, 10 Jan 2011 02:50:01 +0000 (03:50 +0100)
This function takes a region ID and cancels all animations
on or beneath that region (as in push/pop_animatable_region).

First user of this is GtkWidget itself, so unmapped widgets
have looping animations cancelled. Fixes bug #638119, reported
by Jesse van den Kieboom.

docs/reference/gtk/gtk3-sections.txt
gtk/gtk.symbols
gtk/gtkstylecontext.c
gtk/gtkstylecontext.h
gtk/gtkwidget.c

index 3ae7fa806673cc7575e1afa8d0ae8f12ac982238..16372a57673545c07d7951ec35db0b68fb6ed8ef 100644 (file)
@@ -5547,6 +5547,7 @@ gtk_style_context_lookup_icon_set
 gtk_style_context_notify_state_change
 gtk_style_context_pop_animatable_region
 gtk_style_context_push_animatable_region
+gtk_style_context_cancel_animations
 gtk_style_context_remove_provider
 gtk_style_context_remove_provider_for_screen
 gtk_style_context_reset_widgets
index 919ddd4a54bde52ef6750366af8f8b889f65158b..ead590e1a0f9b5815ca1ec64c825a295082683c3 100644 (file)
@@ -2461,6 +2461,7 @@ gtk_style_context_add_class
 gtk_style_context_add_provider
 gtk_style_context_add_provider_for_screen
 gtk_style_context_add_region
+gtk_style_context_cancel_animations
 gtk_style_context_get
 gtk_style_context_get_background_color
 gtk_style_context_get_border
index 162c97136c3eb2a8acda3aff84b85e650d5293ee..3d1b0aa530560ce88b69adfdb10841defa31e7e9 100644 (file)
@@ -454,6 +454,12 @@ struct AnimationInfo
   GtkTimeline *timeline;
 
   gpointer region_id;
+
+  /* Region stack (until region_id) at the time of
+   * rendering, this is used for nested cancellation.
+   */
+  GSList *parent_regions;
+
   GdkWindow *window;
   GtkStateType state;
   gboolean target_value;
@@ -749,6 +755,7 @@ animation_info_free (AnimationInfo *info)
     cairo_region_destroy (info->invalidation_region);
 
   g_array_free (info->rectangles, TRUE);
+  g_slist_free (info->parent_regions);
   g_slice_free (AnimationInfo, info);
 }
 
@@ -1572,7 +1579,6 @@ context_has_animatable_region (GtkStyleContext *context,
                                gpointer         region_id)
 {
   GtkStyleContextPrivate *priv;
-  GSList *r;
 
   /* NULL region_id means everything
    * rendered through the style context
@@ -1581,14 +1587,7 @@ context_has_animatable_region (GtkStyleContext *context,
     return TRUE;
 
   priv = context->priv;
-
-  for (r = priv->animation_regions; r; r = r->next)
-    {
-      if (r->data == region_id)
-        return TRUE;
-    }
-
-  return FALSE;
+  return g_slist_find (priv->animation_regions, region_id) != NULL;
 }
 
 /**
@@ -2919,6 +2918,53 @@ gtk_style_context_notify_state_change (GtkStyleContext *context,
   _gtk_animation_description_unref (desc);
 }
 
+/**
+ * gtk_style_context_cancel_animations:
+ * @context: a #GtkStyleContext
+ * @region_id: (allow-none): animatable region to stop, or %NULL.
+ *     See gtk_style_context_push_animatable_region()
+ *
+ * Stops all running animations for @region_id and all animatable
+ * regions underneath.
+ *
+ * A %NULL @region_id will stop all ongoing animations in @context,
+ * when dealing with a #GtkStyleContext obtained through
+ * gtk_widget_get_style_context(), this is normally done for you
+ * in all circumstances you would expect all widget to be stopped,
+ * so this should be only used in complex widgets with different
+ * animatable regions.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_style_context_cancel_animations (GtkStyleContext *context,
+                                     gpointer         region_id)
+{
+  GtkStyleContextPrivate *priv;
+  AnimationInfo *info;
+  GSList *l, *node;
+
+  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+
+  priv = context->priv;
+  l = priv->animations;
+
+  while (l)
+    {
+      info = l->data;
+      node = l;
+      l = l->next;
+
+      if (!region_id ||
+          info->region_id == region_id ||
+          g_slist_find (info->parent_regions, region_id))
+        {
+          priv->animations = g_slist_remove (priv->animations, info);
+          animation_info_free (info);
+        }
+    }
+}
+
 /**
  * gtk_style_context_push_animatable_region:
  * @context: a #GtkStyleContext
@@ -3096,6 +3142,14 @@ store_animation_region (GtkStyleContext *context,
           rect.height = (gint) height;
 
           g_array_append_val (info->rectangles, rect);
+
+          if (!info->parent_regions)
+            {
+              GSList *parent_regions;
+
+              parent_regions = g_slist_find (priv->animation_regions, info->region_id);
+              info->parent_regions = g_slist_copy (parent_regions);
+            }
         }
     }
 }
index ab9be702e8d4e43bb1c241fb9808aca4e0d138bb..ceedc529c0e8ecc84f64b8785ed314e7f32f3be5 100644 (file)
@@ -522,6 +522,9 @@ void  gtk_style_context_notify_state_change (GtkStyleContext *context,
                                              gpointer         region_id,
                                              GtkStateType     state,
                                              gboolean         state_value);
+void  gtk_style_context_cancel_animations   (GtkStyleContext *context,
+                                             gpointer         region_id);
+
 void gtk_style_context_push_animatable_region (GtkStyleContext *context,
                                                gpointer         region_id);
 void gtk_style_context_pop_animatable_region  (GtkStyleContext *context);
index b7c3141d0de1d8533f76d67520894cdc54e232e7..f0c56b43615e02a3488405d76ba8dc03690362c4 100644 (file)
@@ -4191,6 +4191,9 @@ gtk_widget_unmap (GtkWidget *widget)
       g_signal_emit (widget, widget_signals[UNMAP], 0);
 
       gtk_widget_pop_verify_invariants (widget);
+
+      if (priv->context)
+        gtk_style_context_cancel_animations (priv->context, NULL);
     }
 }